import datetime
from collections import OrderedDict
import common

def calculate_jaccard(data, delta): 
    jaccard_input = common.convert_dict_to_date_router_list(data)
    
    # put the data into N min bins
    bin_data = OrderedDict()
    start_date = min(jaccard_input.keys())
    end_date = max(jaccard_input.keys())
    end_bin_date = start_date + datetime.timedelta(minutes = delta)
    idx = 0
    while start_date < end_date:
        while idx < len(jaccard_input.keys()) and jaccard_input.keys()[idx] < end_bin_date:
            if bin_data.has_key(start_date):
                bin_data[start_date] = bin_data[start_date] + jaccard_input[jaccard_input.keys()[idx]]
            else:
                bin_data[start_date] = jaccard_input[jaccard_input.keys()[idx]]
            idx = idx + 1    
        start_date = end_bin_date
        end_bin_date = start_date + datetime.timedelta(minutes = delta)
        
    keys = bin_data.keys()
    jaccard_values = OrderedDict()
    for i in xrange(0, len(keys) - 1):
        jaccard_values[keys[i]] = compute_jaccard_index(set(bin_data[keys[i]]), set(bin_data[keys[i + 1]]))
    return jaccard_values
    
def calculate_jaccard_weighted(data, counted, delta): 
    jaccard_input =  common.convert_dict_to_date_router_list(data)
    
    # put the data into 5 min bins
    bin_data = OrderedDict()
    start_date = min(jaccard_input.keys())
    end_date = max(jaccard_input.keys())
    end_bin_date = start_date + datetime.timedelta(minutes = delta)
    idx = 0
    while start_date < end_date:
        while idx < len(jaccard_input.keys()) and jaccard_input.keys()[idx] < end_bin_date:
            if bin_data.has_key(start_date):
                bin_data[start_date] = bin_data[start_date] + jaccard_input[jaccard_input.keys()[idx]]
            else:
                bin_data[start_date] = jaccard_input[jaccard_input.keys()[idx]]
            idx = idx + 1    
        start_date = end_bin_date
        end_bin_date = start_date + datetime.timedelta(minutes = delta)
        
    keys = bin_data.keys()
    jaccard_values = OrderedDict()
    for i in xrange(0, len(keys) - 1):
        # prepare set I
        set_a = set(bin_data[keys[i]])
        # prepare set I + 1
        set_b = set(bin_data[keys[i + 1]])
        jaccard_values[keys[i]] = compute_jaccard_index_weighted(set_a, set_b, counted)
    return jaccard_values
 
def compute_jaccard_index_weighted(set_1, set_2, counted):   
    intersection = set_1.intersection(set_2)

    intersection_weight = weighted(intersection, counted)
    union_weight = float(weighted(set_1, counted) + weighted(set_2, counted) - intersection_weight)
    if union_weight == 0:
        return 1
    return intersection_weight / union_weight

def weighted(data_set, counted):
    weight = 0
    for item in data_set:
        if counted.has_key(item):
            weight = weight + counted[item]
        else:
            weight = weight + 1
    return weight
    
def calculate_jaccard_difference(data, num):
    data_diff = OrderedDict()
    for idx in xrange(0, len(data.keys()) - num):
        data_diff[data.keys()[idx]] = data[data.keys()[idx]] - data[data.keys()[idx + num]]
    return data_diff
    
def compute_jaccard_index(set_1, set_2):
    n = len(set_1.intersection(set_2))
    if float(len(set_1) + len(set_2) - n) == 0:
        return 0
    return n / float(len(set_1) + len(set_2) - n)
    